# Makefile for your project
# 定义删除命令
ifdef SystemRoot
    RM = del /Q
    MKDIR = mkdir
    FIXPATH = $(subst /,\,$1)
else
    RM = rm -f
    MKDIR = mkdir -p
    FIXPATH = $1
endif

PREFIX = 
# Compiler 编译器
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
CXX = $(GCC_PATH)/$(PREFIX)g++
else
CC = $(PREFIX)gcc
CXX = $(PREFIX)g++
endif


# debug build?
DEBUG := 1

ifeq ($(DEBUG), 1)
OPT := -O0 -g -gdwarf-2
endif

ifeq ($(DEBUG), 0)
# optimization
OPT := -O2
endif

# 指定生成的可执行文件中字符串常量的字符集编码。
CHARSET += -fexec-charset=utf-8
# 指定源代码文件的字符集编码
# CHARSET += -finput-charset=gbk


# C语言与C++的版本
C_VER := -std=c99
CXX_VER := -std=c++11
# CXX_VER := -std=c++17 -Wno-register


BUILD_DIR := build
TARGET_DIR := $(BUILD_DIR)
TARGET := $(TARGET_DIR)/application # 可执行文件名称

all: $(TARGET)


# C defines
C_DEFS = 



# Compiler flags 编译器标志
CFLAGS += -Wall -Wextra
# 禁用未使用参数的警告
CFLAGS += -Wno-unused-parameter
# 禁用未使用函数的警告
CFLAGS += -Wno-unused-function
# 禁用关于误导性缩进的警告。
CFLAGS += -Wno-misleading-indentation
# 禁用有关隐式控制流穿透的警告
# 当一个switch语句中的case标签没有显式地使用break语句时，编译器会发出隐式贯穿警告
# CFLAGS += -Wno-implicit-fallthrough

# 用于指定执行字符集
CFLAGS += $(CHARSET)


# 通过 find 命令递归地搜索的根目录路径，可以是多个但别重复冲突
FIND_SRC_DIRS := ./src ./inc
FIND_SRC_DIRS += ./app

# VPATH 告诉 make 在哪里寻找源文件 VPATH是makefile中的特殊变量
# 通过 find 命令递归地搜索所有的目录类型文件(-type d)
VPATH := $(shell find $(FIND_SRC_DIRS) -type d)
C_PATH += $(VPATH)
CXX_PATH += $(VPATH)

INCLUDES_FLAG := -I
CFLAGS += $(C_DEFS) $(OPT)
CXXFLAGS := $(CFLAGS)

#######################################
# 添加头文件路径 c的步骤
#######################################
# 添加 -I 标志来指定每个头文件目录
C_INCLUDES += $(foreach dir,$(C_PATH),$(INCLUDES_FLAG)$(dir))

CFLAGS += $(C_INCLUDES)
#######################################
# 添加源文件路径 c的步骤
#######################################
# 通过 find 命令递归地搜索所有的 .c文件
# Source files 源文件
C_SRCS := $(shell find $(FIND_SRC_DIRS) -name "*.c")
C_SOURCES += $(C_SRCS)

# list of c objects    
# 这行代码的作用是将C_SOURCES中的所有.c文件名转换为.o文件名，并在每个文件名前添加$(BUILD_DIR)/前缀
OBJS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
# 这行代码的作用是设置%.c文件的搜索路径。
# vpath函数用于指定在哪些目录中查找指定的文件。
# sort函数用于对目录进行排序，以确保搜索顺序是一致的。


#######################################
# 添加头文件路径 cpp的步骤
#######################################
# 添加 -I 标志来指定每个头文件目录
CXX_INCLUDES += $(foreach dir,$(CXX_PATH),$(INCLUDES_FLAG)$(dir))
CXXFLAGS += $(CXX_INCLUDES)

#######################################
# 添加源文件路径 cpp的步骤
#######################################
# 通过 find 命令递归地搜索所有的.cpp 文件
CXX_SRCS := $(shell find $(FIND_SRC_DIRS) -name "*.cpp")
CXX_SOURCES += $(CXX_SRCS)

# list of cpp objects 
CXX_OBJS += $(addprefix $(BUILD_DIR)/,$(notdir $(CXX_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CXX_SOURCES)))



# 标准库或者系统api库
LIBDIR +=
LIBS += -lm					# 标准数学库 libm
LIBS += -lpthread
LDFLAGS += $(LIBDIR) $(LIBS)

# 链接
# 生成可执行文件
$(TARGET): $(CXX_OBJS) $(OBJS)
	@$(CXX) $(CXXFLAGS) $(CXX_VER) -o $@ $^ $(LDFLAGS)
	@echo 
	@echo $(CXX) linking $@
	@echo
	
######## c
# Build rule for object files 目标文件的构建规则(编译)
# Makefile 作为依赖项表示Makefile若被修改那么这个规则会被重新执行，即使它所依赖的源文件（%.c）没有发生变化。
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
	@$(CC) $(CFLAGS) $(C_VER) -o $@ -c $<
	@echo $(CC) Compiler $@

######## cpp
# Build rule for object files 目标文件的构建规则(编译)
# Makefile 作为依赖项表示Makefile若被修改那么这个规则会被重新执行，即使它所依赖的源文件（%.c）没有发生变化。
$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR)
	@$(CXX) $(CXXFLAGS) $(CXX_VER) -o $@ -c $<
	@echo $(CXX) Compiler $@

# # 汇编
# # 生成目标文件的编译规则
# $(BUILD_DIR)/%.o: $(BUILD_DIR)/%.s | $(BUILD_DIR)
# 	@$(CC) -c $< -o $@
# 	@echo Compiler $@

# # 编译
# # 生成汇编文件的编译规则
# $(BUILD_DIR)/%.s: $(BUILD_DIR)/%.i | $(BUILD_DIR)
# 	@$(CC) -S $(CFLAGS) $(C_VER) $< -o $@
# #	@echo Assemble $@

# # 预处理
# # 生成预处理文件的规则
# $(BUILD_DIR)/%.i: %.c Makefile | $(BUILD_DIR)
# 	@$(CC) -E $(CFLAGS) $(C_VER) $< -o $@
# #	@echo Preprocess  $@


$(BUILD_DIR):
	$(MKDIR) $@


# .SECONDARY: $(BUILD_DIR)/%.i $(BUILD_DIR)/%.s $(BUILD_DIR)/%.o

# Phony target to clean the project 伪目标，用于清理项目
.PHONY: clean
# clean:
# 	$(RM) $(call FIXPATH,$(TARGET))
# 	$(RM) $(call FIXPATH,$(OBJS))
clean:
	$(RM) $(BUILD_DIR)/*

